#include <unistd.h>
#include <fcntl.h>
#include <sys/eventfd.h>
#include <memory>

#include "eventloop.h"
#include "logger.h"

// 防止一个线程创建多个EventLoop 
__thread EventLoop* t_loopInThisThread = nullptr;

// 默认的Poller的IO复用超时事件
const int kPollTimeMs = 10000;

// 创建weakupfd, 用来唤醒
int createEventfd(){
    int etvfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
    if(etvfd < 0){
        LOG_FATAL("eventfd error:%d", errno);
    }
    return etvfd;
}

EventLoop::EventLoop()
    : looping_(false)
    , quit_(false)
    , callingPendingFunctors_(false)
    , threadId_(CurrentThread::tid())
    , poller_(Poller::newDefaultPoller(this))
    , wakeupFd_(createEventfd())
    , wakeupChannel_(new Channel(this, wakeupFd_))
{
    LOG_INFO("EventLoop created %p in thread %d \n", this, threadId_);
    if(t_loopInThisThread){
        LOG_FATAL("Another EventLoop created %p in thread %d \n", this, threadId_);
    }else{
        t_loopInThisThread = this;
    }

    // 给wakeupfd 的事件类型 以及发生事件后的回调操作
    // 在 epoll_wait 陷入阻塞时， 需要被wakeup
    wakeupChannel_->enableReading();
    wakeupChannel_->setReadCallBack(std::bind(&EventLoop::handleRead, this));

}


EventLoop::~EventLoop(){
    wakeupChannel_->disableAll();
    wakeupChannel_->remove();

    close(wakeupFd_);
    t_loopInThisThread = nullptr;
}

// 给wakeupfd 的读回调操作
// handleRead并不需要做什么特殊的操作
// 因为wakeupFd的作用是 是使得线程从epoll_wait里面苏醒
 void EventLoop::handleRead(){
    uint64_t one = 1;
    int n = read(wakeupFd_, &one, sizeof(one));
    if(n != sizeof(one)){
        LOG_ERROR("%s activate read", __FUNCTION__);
    }
}

/**
 *  loop 的逻辑
 *  1 先进行epoll_wait, 等待事件发生
 *  2 对于触发的事件， 执行其预先触发的回调操作
 *  3 最后 doPendingFunctors(),  相当于每次epoll_wait之后用户设置的回调
 * 
 */
void EventLoop::loop(){
    looping_ = true;
    quit_ = false;
    LOG_INFO("EventLoop %p start looping.", this);
    while(!quit_){
        activateChannels_.clear();
        pollReturnTime_ = poller_->poll(kPollTimeMs, &activateChannels_);

        // 处理事件
        for(Channel* channel : activateChannels_){
            // Poller 监听那些channel发生了事件
            channel->handlerEvent(pollReturnTime_);
        }


        // 执行当前EventLoop事件需要处理的回调操作
        doPendingFunctors();
    }

    
}

void EventLoop::quit(){
    quit_ = true;

    if(!isInLoopThread()){
        wakeup();
    }
}

void EventLoop::runInLoop(Functor cb){
    if(isInLoopThread()){
        cb();
    }else{
       // 不在loop线程里面, 就需要唤醒loop所在的线程执行
        queueInLoop(cb);
    }
}
// 把cb放入队列中，  唤醒loop所在的线程， 执行cb
void EventLoop::queueInLoop(Functor cb){
    {
        std::unique_lock<std::mutex> lock(mutex_);
        pendingFunctors_.push_back(cb);
    }

    // 唤醒相应的线程
    // callingPendingFunctors_ 为 true ，说明正在执行回调
    // 执行完回调， 这会阻塞在epoll_wait 里面
    // 因此 还需要将其唤醒, 保证其唤醒执行这个回调
    if(!isInLoopThread() || callingPendingFunctors_){
        wakeup();
    }
}


void EventLoop::wakeup(){
    // 唤醒执行loop线程的方法
    uint64_t one = 1;
    int n = write(wakeupFd_, &one, sizeof(one));
    LOG_INFO("EventLoop::wakeup\n");
    if(n != sizeof(one)){
        LOG_ERROR("EventLoop::wakeup() writes error,  wites %d bytes instead of 8\n", n);
    }
}

void EventLoop::updateChannel(Channel* channel){
    poller_->updateChannel(channel);
}
void EventLoop::removeChannel(Channel* channel){
    poller_->removeChannel(channel);
}
bool EventLoop::hasChannel(Channel* channel){
    return poller_->hasChannel(channel);
}

// 执行用户回调逻辑

void EventLoop::doPendingFunctors(){
    std::vector<Functor> functors;
    // 1 表示此时的线程正在处理用户回调
    callingPendingFunctors_ = true;

    // 2 把用户回调存在副本里面， 这里使用副本执行， 
    // 避免pendingFunctors_的执行的时候无法并发添加用户回调
    {
        std::unique_lock<std::mutex> lock(mutex_);
        functors.swap(pendingFunctors_);
    }

    for(auto& functor : functors){
        functor();
    }

    callingPendingFunctors_ = false;


}


